/**
      <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <2011>  <André Mendes de Oliveira Paiva>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  
 */

package estrutura.lista;

import estrutura.No;
import java.util.ArrayList;


public class NoLista extends No {

    private ArestaLista aresta;

    public NoLista(int id, String valor, ArestaLista aresta) {
        super(id, valor);
        this.setAresta(aresta);
    }

    public NoLista(int id, String valor) {
        this(id, valor, null);
    }

    public void setAresta(ArestaLista aresta) {
        this.aresta = aresta;
    }

    public ArestaLista getAresta() {
        return this.aresta;
    }

    public ArestaLista obterAresta(int idNoDestino) {
        ArestaLista arestaPesq = this.getAresta();
        if (arestaPesq != null) {
            /* Procura por ligação com Id do nó destino igual a idNoDestino */
            while (arestaPesq != null) {
                if (arestaPesq.getNoDestino().getId() == idNoDestino) {
                    break;
                }
                arestaPesq = arestaPesq.getProxAresta();
            }
        }
        return arestaPesq;
    }

    public boolean addAresta(NoLista noDestino, Object rotulo, int peso) {
        /* verifia se existe aresta */
        boolean ret = false;
        /* o nó não possui aresta, então cria aresta e liga ao nó destino */
        if (this.getAresta() == null) {
            ArestaLista novaAresta = new ArestaLista(noDestino, null, rotulo, peso);
            this.setAresta(novaAresta);
            ret = true;
        } else if (this.obterAresta(noDestino.getId()) == null) {
            /* procura pela última aresta ligada ao nó */
            ArestaLista arestaPesq = this.getAresta();
            while (arestaPesq.getProxAresta() != null) {
                arestaPesq = arestaPesq.getProxAresta();
            }
            ArestaLista novaAresta = new ArestaLista(noDestino, null, rotulo, peso);
            arestaPesq.setProxAresta(novaAresta);
            ret = true;
        }
        noDestino = null;
        return ret;
    }

    public boolean addAresta(NoLista noDestino, Object rotulo) {
        return addAresta(noDestino, rotulo, 0);
    }

    public boolean addAresta(NoLista noDestino) {
        return addAresta(noDestino, null, 0);
    }

    public boolean addRotulo(int idNoDestino, Object rotulo) {
        boolean ret = false;
        ArestaLista arestaPesq = this.obterAresta(idNoDestino);
        if (arestaPesq != null) {
            if (arestaPesq.getRotulo() == null) {
                arestaPesq.setRotulo(rotulo);
                ret = true;
            } else {
                System.out.println("Rotulo ja cadastrado para a aresta!");
            }
        }
        return ret;
    }

    public boolean removeRotulo(int idNoDestino) {
        /* verifica se existe aresta */
        boolean ret = false;
        ArestaLista arestaPesq = this.obterAresta(idNoDestino);
        if (arestaPesq != null) {
            if (arestaPesq.getRotulo() == null) {
                //System.out.println("Rotulo não encontrado!");
            } else {
                arestaPesq.setRotulo(null);
                ret = true;
            }
        }
        return ret;
    }

    public boolean removeAllAresta() {
        boolean ret = false;
        /* exclui todas as arestas do nó */
        ArestaLista arestaCor = this.getAresta();
        while (arestaCor != null) {
            ret = this.removeAresta(arestaCor.getNoDestino().getId());
            arestaCor = arestaCor.getProxAresta();
        }
        arestaCor = null;
        return ret;
    }

    public boolean removeAresta(int idNoDestino) {
        /* verifia se existe aresta */
        boolean ret = false;
        if (this.getAresta() != null) {
            /* Procura por ligação entre os dois nós */
            ArestaLista arestaAnt = null;
            ArestaLista arestaCor = this.getAresta();
            while (arestaCor.getNoDestino().getId() != idNoDestino && arestaCor.getProxAresta() != null) {
                arestaAnt = arestaCor;
                arestaCor = arestaCor.getProxAresta();
            }
            /* achou ligação, então deve ser excluida */
            if (arestaCor.getNoDestino().getId() == idNoDestino) {
                /* achou a aresta e é a primeira aresta */
                if (arestaAnt == null) {
                    this.setAresta(arestaCor.getProxAresta());
                } else /* exclui a aresta corrente */ {
                    arestaAnt.setProxAresta(arestaCor.getProxAresta());
                }
                ret = true;
            }
            arestaAnt = null;
            arestaCor = null;
        }
        return ret;
    }

    @Override
    public void imprimir() {
        System.out.println(this.toString());
    }

    public void imprimir(boolean incluiRotulo) {
        System.out.println(this.toString(incluiRotulo));
    }

    @Override
    public String toString() {
        return this.toString(true);
    }

    public String toString(boolean incluiRotulo) {
        String res = super.toString();
        if (this.getAresta() == null) {
            //res += "\n<Nao possui arestas>";
            res += "";
        } else {
            res += "\n  Arestas:";
            ArestaLista arestaAtual = this.getAresta();
            /* Percorre as arestas e obtem o resultado em String os dados das mesmas */
            while (arestaAtual != null) {
                res += "\n    Valor: " + arestaAtual.getNoDestino().getValor();
                /* Se existir o rotulo, imprime a descrição dele */
                if (incluiRotulo && arestaAtual.getRotulo() != null) {
                    res += " - Rotulo: " + arestaAtual.getRotulo().toString();
                }
                arestaAtual = arestaAtual.getProxAresta();
            }
        }
        return res;
    }
    /* Retorna o ID da primeira Aresta encontrada ou -1 senão existir aresta*/
    public int getIDPrimeiraAresta() {
        int id = -1;
        if (this.getAresta() != null) {
            id = this.getAresta().getNoDestino().getId();
        }
        return id;
    }
    /* Retorna o ID da próxima Aresta encontrada ou -1 senão existir aresta*/
    public int getIDProximaAresta(int idNoDestino) {
        int id = -1;
        ArestaLista arestaPesq = this.obterAresta(idNoDestino);
        if (arestaPesq != null && arestaPesq.getProxAresta() != null) {
            id = arestaPesq.getProxAresta().getNoDestino().getId();
        }
        return id;
    }
    /* Retorna o rotulo da ligação ou null senão não existir aresta*/
    public Object getRotuloAresta(int idNoDestino) {
        ArestaLista arestaPesq = this.obterAresta(idNoDestino);
        if (arestaPesq != null && arestaPesq.getRotulo() != null) {
            return arestaPesq.getRotulo();
        }
        return null;
    }

    /* Retorna lista de Nos Vizinhos*/
    public ArrayList<No> obterNosVizinhos()  {
        ArrayList<No> listaNo = new ArrayList<No>();
        if (this.getAresta() != null) {
            ArestaLista arestaCor = this.getAresta();
            while (arestaCor != null) {
                listaNo.add(arestaCor.getNoDestino());
                arestaCor = arestaCor.getProxAresta();
            }
        }
        return listaNo;
    }
}
